%{
#include <stdio.h>
#include <ctype.h>
//#include <stack>
#include "GrammarAnalyzer.h"

//std::stack<int> dtStack;
//static int dataType;
void yyerror(char *s);
int yylex(void);
extern char *yytext;
extern int yylineno;
static int  globalVariable_number=0;
const SYMBOL *pSym;
#define abs(a) ((a<0)?-(a):a)
%}

%token INT_NUMBER FLOAT_NUMBER
%token ID
%token INT
%token FLOAT
%token MAIN
%token IF ELSE WHILE BREAK CONTINUE RETURN
%token ASSIGN PLUS MINUS TIMES OVER 
%token EQ LT LE
%token LPAREN RPAREN
%token SEMI COMMA


%start CProgram

%%

CProgram	: NonMainCode MainFunction {}
		;

NonMainCode	: NonMainCode GlobalVariableDefine {}
		| NonMainCode NonMainFunction	   {}
		| 				   {}
		;

GlobalVariableDefine : DataType ID '=' ConstExpression ';' 
		{
			pST->insertVar($2.strVal, $1.type);
			pSym = pST->searchVar($2.strVal);
			if($1.type == $4.type) {
				if($1.type == INT) {
					pTCG->op("iset", pSym->getStrAddr(), $4.intVal);
				}else{
					pTCG->op("fset", pSym->getStrAddr(), $4.doubleVal);
				}
			}else{
				if($1.type == INT) {
					throw " float->int";
				}else{
					pTCG->op("fset", pSym->getStrAddr(), (double)($4.intVal));
				}
	
			}
			pST->printTable();
		}
		;

NonMainFunction : NonMainFunctionHeader LBracket Declarations Statements RBracket
		{
		}
		;
NonMainFunctionHeader : DataType ID '(' ArgumentLists ')'					
		{
			pST->insertFunc($2.strVal, $1.type, pTCG->func_begin());
			pST->printTable();
		}
		;

MainFunction    : MainFunctionHeader LBracket Declarations Statements RBracket
		{
		}
		;
MainFunctionHeader	: DataType MAIN '(' ArgumentLists ')'					
		{
			pST->insertFunc("main", $1.type, pTCG->main_begin());
			pST->printTable();
		}
		;

ArgumentLists	: addArgumentLists DataType ID	
		{
			pST->insertPara($3.strVal, $2.type);
		}
		|			{}
		;

addArgumentLists: addArgumentLists DataType ID ',' 
		{
			pST->insertPara($3.strVal, $2.type);
		}
		| 			{}
		;

Declarations 	: Declarations DataType ID ';'     
		{
			pST->insertVar($3.strVal, $2.type);
			pST->printTable();
		}
		|			{}
		;

Statements	: Statements Statement  {}
		|
		;

Statement	: Assignment 		{}
		| ifStatement		{}
		| whileStatement	{}
		| returnStatement	{}
		| FuncCall ';'		{}
		| LBracket Declarations Statements RBracket {}
		| ';'			{}
		;

Assignment	: ID '=' Expression ';'		
		{
			std::string idAddr;
			pSym = pST->searchVar($1.strVal);
			idAddr = pSym->getStrAddr();
			$1.type = pSym->dataType;
			if($1.type == $3.type){
				if($1.type = INT) {
					pTCG->op("i=",idAddr,$3.strVal);
				}else{
					pTCG->op("f=",idAddr,$3.strVal);
				}
			}else {
				if($1.type = INT) {
					throw "float -> int";
				}else{
					pTCG->op("f<-i", idAddr, $3.strVal);
				}
			}
		pST->deleteTemp();

		}
		;
ifStatement	: ifStatementBegin Statement  
		{
			pTCG->if_end();
		}
		| ifStatementBegin elseBegin Statement 
		{
			pTCG->if_else_end();
		}
		;
ifStatementBegin: IF '(' ConditionExpression ')'
		{
			pTCG->if_begin($3.strVal);
			pST->deleteTemp();
		}
		;
elseBegin	: Statement ELSE
		{
			pTCG->else_begin();

		}
		;
whileStatement  : whileStatementBegin whileCondition Statement
		{
			pTCG->while_end();
		}
whileStatementBegin  : WHILE
		{
			pTCG->while_begin();
		}
		;
whileCondition	: '(' ConditionExpression ')'
		{
			pTCG->while_condition($2.strVal);
			pST->deleteTemp();
		}
		;

returnStatement : RETURN ';'			
		{
			pTCG->return_void();
		}
		| RETURN '(' Expression ')' ';' 
		{
			pTCG->return_value($3.strVal);
			pST->deleteTemp();
		}
		;
FuncCall	: FuncName '(' RealArgLists ')'
		{
		}
		;
RealArgLists	: RealArgList Expression
		{
		}
		|		{}
		;

RealArgList	: RealArgList Expression ','
		{
		}
		|		{}
		;
FuncName	: ID
		{
		}
		;
ConditionExpression : Expression EQ Expression   
		{
			$$.type = INT;
			$$.strVal = pST->newTemp();
			if($1.type == $3.type){
				if($1.type = INT) {
					pTCG->op("i==", $$.strVal, $1.strVal, $3.strVal);
				}else{
					pTCG->op("f==", $$.strVal, $1.strVal, $3.strVal);
				}
			}else {
				std::string tmpAddr = pST->newTemp();
				if($1.type = INT) {
					pTCG->op("f<-i", tmpAddr, $1.strVal);
					pTCG->op("f==", $$.strVal, tmpAddr, $3.strVal);
				}else{
					pTCG->op("f<-i", tmpAddr, $3.strVal);
					pTCG->op("f==", $$.strVal, $1.strVal, tmpAddr);
				}
			}
		}
		    | Expression LT Expression   
		{
			$$.type = INT;
			$$.strVal = pST->newTemp();
			if($1.type == $3.type){
				if($1.type = INT) {
					pTCG->op("i<", $$.strVal, $1.strVal, $3.strVal);
				}else{
					pTCG->op("f<", $$.strVal, $1.strVal, $3.strVal);
				}
			}else {
				std::string tmpAddr = pST->newTemp();
				if($1.type = INT) {
					pTCG->op("f<-i", tmpAddr, $1.strVal);
					pTCG->op("f<", $$.strVal, tmpAddr, $3.strVal);
				}else{
					pTCG->op("f<-i", tmpAddr, $3.strVal);
					pTCG->op("f<", $$.strVal, $1.strVal, tmpAddr);
				}
			}
		}
		    | Expression LE Expression   
		{
			$$.type = INT;
			$$.strVal = pST->newTemp();
			if($1.type == $3.type){
				if($1.type = INT) {
					pTCG->op("i<=", $$.strVal, $1.strVal, $3.strVal);
				}else{
					pTCG->op("f<=", $$.strVal, $1.strVal, $3.strVal);
				}
			}else {
				std::string tmpAddr=pST->newTemp();
				if($1.type = INT) {
					pTCG->op("f<-i", tmpAddr, $1.strVal);
					pTCG->op("f<=", $$.strVal, tmpAddr, $3.strVal);
				}else{
					pTCG->op("f<-i", tmpAddr, $3.strVal);
					pTCG->op("f<=", $$.strVal, $1.strVal, tmpAddr);
				}
			}
		}
		    ;

Expression	: Expression '+' Term		
		{
			$$.strVal = pST->newTemp();
			if($1.type == $3.type){
				$$.type = $1.type;
				if($1.type = INT) {
					pTCG->op("i+", $$.strVal, $1.strVal, $3.strVal);
				
				}else{
					pTCG->op("f+", $$.strVal, $1.strVal, $3.strVal);
				}
			}else {
				$$.type = FLOAT;
				if($1.type = INT) {
					pTCG->op("f<-i", $$.strVal, $1.strVal);
					pTCG->op("f+", $$.strVal, $$.strVal, $3.strVal);
				}else{
					pTCG->op("f<-i", $$.strVal, $3.strVal);
					pTCG->op("f+", $$.strVal, $1.strVal, $$.strVal);
				}
			}
		}
		| Expression '-' Term		
		{
			$$.strVal = pST->newTemp();
			if($1.type == $3.type){
				$$.type = $1.type;
				if($1.type = INT) {
					pTCG->op("i-", $$.strVal, $1.strVal, $3.strVal);
				}else{
					pTCG->op("f-", $$.strVal, $1.strVal, $3.strVal);
				}
			}else {
				$$.type = FLOAT;
				if($1.type = INT) {
					pTCG->op("f<-i", $$.strVal, $1.strVal);
					pTCG->op("f-", $$.strVal, $$.strVal, $3.strVal);
				}else{
					pTCG->op("f<-i", $$.strVal, $3.strVal);
					pTCG->op("f-", $$.strVal, $1.strVal, $$.strVal);
				}
			}
		}
		| Term				
		{
			$$.type = $1.type;
			$$.strVal = $$.strVal;
		}
		;

Term		: Term '*' Factor		
		{
			$$.strVal = pST->newTemp();
			if($1.type == $3.type){
				$$.type = $1.type;
				if($1.type = INT) {
					pTCG->op("i*",$$.strVal, $1.strVal, $3.strVal);
				}else{
					pTCG->op("f*", $$.strVal, $1.strVal, $3.strVal);
				}
			}else {
				$$.type = FLOAT;
				if($1.type = INT) {
					pTCG->op("f<-i", $$.strVal, $1.strVal);
					pTCG->op("f*", $$.strVal, $$.strVal, $3.strVal);
				}else{
					pTCG->op("f<-i", $$.strVal, $3.strVal);
					pTCG->op("f*", $$.strVal, $1.strVal, $$.strVal);
				}
			}
		}
		| Term '/' Factor		
		{
			$$.strVal = pST->newTemp();
			if($1.type == $3.type){
				$$.type = $1.type;
				if($1.type = INT) {
					pTCG->op("i/", $$.strVal, $1.strVal, $3.strVal);
				}else{
					pTCG->op("f/", $$.strVal, $1.strVal, $3.strVal);
				}
			}else {
				$$.type = FLOAT;
				if($1.type = INT) {
					pTCG->op("f<-i", $$.strVal, $1.strVal);
					pTCG->op("f/", $$.strVal, $$.strVal, $3.strVal);
				}else{
					pTCG->op("f<-i", $$.strVal, $3.strVal);
					pTCG->op("f/", $$.strVal, $1.strVal, $$.strVal);
				}
			}
		}
		| Factor			
		{
			$$.type = $1.type;
			$$.strVal = $1.strVal;
		}
		;
Factor		: ConstExpression		
		{
			$$.type = $1.type;//取类型的相反数表明为常量值
			$$.strVal = pST->newTemp();
			if($1.type == INT){
				pTCG->op("iset", $$.strVal, $1.intVal);
			}else{
				pTCG->op("fset", $$.strVal, $1.doubleVal);
			}
		}
		| ID				
		{
			pSym = pST->searchVar($1.strVal);	
			$$.type = pSym->dataType;
			$$.strVal = pSym->getStrAddr();
		}
		| FuncCall
		{
		}
		;
		| '(' Expression ')'		
		{
			$$.type = $2.type;
			$$.strVal = $2.strVal;
		}
		;

ConstExpression	: ConstExpression '+' ConstTerm  
		{ 
			switch($1.type) {
				case INT:
					if($3.type==FLOAT) {
						$$.type = FLOAT;
						$$.doubleVal = $1.intVal + $3.doubleVal;
					}else{
						$$.type = INT;
						$$.intVal = $1.intVal + $3.intVal;
					}
					break;
					
				case FLOAT:
					if($3.type == FLOAT){
						$$.doubleVal = $1.doubleVal + $3.doubleVal;
					}else{
						$$.doubleVal = $1.doubleVal + $3.intVal;
					}
					$$.type = FLOAT;
					break;
				default:
					throw "unknow const type";
			}
		}
		| ConstExpression '-' ConstTerm  
		{ 
			switch($1.type) {
				case INT:
					if($3.type==FLOAT) {
						$$.type = FLOAT;
						$$.doubleVal = $1.intVal - $3.doubleVal;
					}else{
						$$.type = INT;
						$$.intVal = $1.intVal - $3.intVal;
					}
					break;
					
				case FLOAT:
					if($3.type == FLOAT){
						$$.doubleVal = $1.doubleVal - $3.doubleVal;
					}else{
						$$.doubleVal = $1.doubleVal - $3.intVal;
					}
					$$.type = FLOAT;
					break;
				default:
					throw "unknow const type";
			}
		}
		| ConstTerm			
		{ $$ = $1;}
		;
ConstTerm	: ConstTerm '*' ConstFactor 
		{ 
			switch($1.type) {
				case INT:
					if($3.type==FLOAT) {
						$$.type = FLOAT;
						$$.doubleVal = $1.intVal * $3.doubleVal;
					}else{
						$$.type = INT;
						$$.intVal = $1.intVal * $3.intVal;
					}
					break;
					
				case FLOAT:
					if($3.type == FLOAT){
						$$.doubleVal = $1.doubleVal * $3.doubleVal;
					}else{
						$$.doubleVal = $1.doubleVal * $3.intVal;
					}
					$$.type = FLOAT;
					break;
				default:
					throw "unknow const type";
			}
		}
		| ConstTerm '/' ConstFactor 
		{ 
			if(($3.type == INT && $3.intVal == 0)
				|| ($3.type == FLOAT && $3.doubleVal == 0))
				throw "dived by 0";
			switch($1.type) {
				case INT:
					if($3.type==FLOAT) {
						$$.type = FLOAT;
						$$.doubleVal = $1.intVal / $3.doubleVal;
					}else{
						$$.type = INT;
						$$.intVal = $1.intVal / $3.intVal;
					}
					break;
					
				case FLOAT:
					if($3.type == FLOAT){
						$$.doubleVal = $1.doubleVal / $3.doubleVal;
					}else{
						$$.doubleVal = $1.doubleVal / $3.intVal;
					}
					$$.type = FLOAT;
					break;
				default:
					throw "unknow const type";
			}
		}
		| ConstFactor		  
		{ 
			$$ = $1;
		}
		;
ConstFactor	: INT_NUMBER		
		{ 
			$$.intVal = $1.intVal;
			$$.type = INT;
		}
		| FLOAT_NUMBER
		{ 
			$$.doubleVal = $1.doubleVal;
			$$.type = FLOAT;
		}
		| '(' ConstExpression ')'	    
		{ 
			$$ = $2;
		}
		;

DataType	: INT		{ $$.type = INT; }
		| FLOAT		{ $$.type = FLOAT; }
		;
LBracket	: '{' 		{ pST->inBracket();}
		;
RBracket	: '}' 		{ pST->outBracket();}
		;

%%
void yyerror(char *s)
{
	printf("yyerror: %d : %s\n", yylineno, s);
}
